<template>
  <div class="table-wrapper">
    <div class="tools-bar">
      <el-tooltip effect="dark" content="刷新表格" placement="top">
        <el-button size="mini" class="el-icon-refresh-left" @click.native="dataFresh()" />
      </el-tooltip>
      <el-tooltip effect="dark" content="过滤表格" placement="top">
        <el-popover
          width="80px"
          trigger="click">
          <el-checkbox
            :indeterminate="isIndeterminate"
            @change="handleCheckAllChange"
            v-model="checkAll"
          >
            全选
          </el-checkbox>
          <el-checkbox-group v-model="checkboxProp" class="filter-wrapper" :min="1">
            <el-checkbox v-for="item of tableProps" :label="item.label" :key="item.index" checked>{{ item.label }}</el-checkbox>
            <el-checkbox v-if="$slots.tool" :label="toolsTitle" checked></el-checkbox>
          </el-checkbox-group>
          <el-button size="mini" class="el-icon-s-grid" slot="reference" />
        </el-popover>
      </el-tooltip>
      <el-tooltip effect="dark" content="导出excel" placement="top">
        <el-button size="mini" @click="exportExcel" class="el-icon-tickets" />
      </el-tooltip>
    </div>
    <el-table
      ref="table"
      :data="dataSource"
      :row-key="rowKey"
      v-loading="loading"
      :size="size"
      :default-expand-all="defaultExpandAll"
      @row-click="$emit('rowClick', arguments)"
      :tree-props="treeProps">
      <template v-for="(item, index) of tableProps">
        <el-table-column
          :prop="item.index"
          :key="index"
          :label="item.label"
          v-bind="item.conf"
          v-if="firstRender || checkboxProp.includes(item.label)"
        >
          <template slot-scope="scope">
            <span v-if="item.dict">
              <!-- 字典实时渲染 在vuex于当前组件状态中获取 （插值表达式保证实时更新） -->
              {{ $store.state.common.tableDict[item.dict] ? $store.state.common.tableDict[item.dict][scope.row[item.index]] :
                (dict[item.dict] ? dict[item.dict][scope.row[item.index]] : '字典失效') }}
            </span>
            <span v-else>{{ scope.row[item.index] || '空' }}</span>
          </template>
        </el-table-column>
      </template>
      <slot name="tool" v-if="firstRender || checkboxProp.includes(toolsTitle)"></slot>
    </el-table>
    <ms-pagination v-if="pagination" @changeCurrentPage="handleChangeData" :count="count" @changePageSize="handleChangeSize"/>
  </div>
</template>

<script>
import FileSaver from 'file-saver'
import XLSX from 'xlsx'
import { getPageData } from '@/api/common/page'
import { getDictByKeys } from '@/api/sys/dict'
import MsPagination from './MsPagination'
export default {
  components: {
    MsPagination
  },
  props: {
    tableProps: {
      type: Array,
      required: true
    },
    dataApi: {
      type: String,
      require: true
    },
    treeProps: {
      type: Object
    },
    rowKey: {
      type: String,
      default: 'id'
    },
    pagination: {
      type: Boolean,
      default: true
    },
    size: {
      type: String,
      default: 'medium'
    },
    defaultExpandAll: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      dataSource: [],
      count: 0,
      pages: {
        page: 1,
        limit: 10,
        info: {}
      },
      loading: true,
      dict: {},
      // 修复初始渲染闪动
      firstRender: true,
      checkboxProp: [],
      isIndeterminate: false,
      checkAll: true
    }
  },
  computed: {
    // 全部选中数组
    checkAllOption() {
      const allProp = this.tableProps.map((item) => item.label)
      const toolsTitle = this.toolsTitle
      if (toolsTitle) {
        allProp.push(toolsTitle)
      }
      return allProp
    },
    toolsTitle() {
      return this.$slots.tool && this.$slots.tool[0].componentOptions.propsData.label
    }
  },
  mounted() {
    this.firstRender = false
    console.log(this.$slots)
  },
  methods: {
    async dataFresh(page = this.pages.page, limit = this.pages.limit, info = this.pages.info) {
      this.loading = true
      // merge查询
      const obj = { page, limit, ...info }
      this.handleGetDictVal().then(() => {
        getPageData(this.dataApi, obj).then((res) => {
          this.dataSource = res.obj.records
          this.count = res.obj.total
        }).finally(() => {
          this.loading = false
        })
      })
    },
    handleChangeData(val) {
      this.pages.page = val
      this.dataFresh(val)
    },
    handleChangeSize(val) {
      this.pages.limit = val
      this.dataFresh(this.pages.page, val)
    },
    // 获取字典数据并处理
    async handleGetDictVal() {
      const keys = this.formatDict(this.tableProps.map((item) => item.dict).filter(item => item))
      // 是否有需要获取字典
      if (keys) {
        await getDictByKeys(keys).then(res => {
          const { obj } = res
          if (obj) {
            const dictDatas = {}
            Object.keys(obj).forEach((key) => {
              const dictData = {}
              obj[key].forEach((innerItem) => {
                const { code, dictValue } = innerItem
                dictData[code] = dictValue
              })
              dictDatas[key] = dictData
            })
            this.$store.commit('common/SET_TABLE_DATA', dictDatas)
            this.dict = dictDatas
          }
        })
      }
    },
    // 过滤需要查询的字典
    formatDict(keys) {
      const tableDict = this.$store.state.common.tableDict
      Object.keys(tableDict).forEach((key) => {
        if (tableDict[key]) {
          keys.splice(keys.indexOf(key), 1)
        }
      })
      return keys.join(',')
    },
    // 过滤全选
    handleCheckAllChange(val) {
      const checkAllOption = this.checkAllOption
      this.checkboxProp = val ? checkAllOption : [checkAllOption[0]]
      this.isIndeterminate = this.checkAll = val
    },
    exportExcel() {
      var wb = XLSX.utils.table_to_book(this.$refs.table.$el)
      debugger
      var wbout = XLSX.write(wb, { bookType: 'xlsx', bookSST: true, type: 'array' })
      try {
        FileSaver.saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'sheetjs.xlsx')
      } catch (e) { if (typeof console !== 'undefined') console.log(e, wbout) }
      return wbout
    }
  }
}
</script>

<style lang="stylus" scoped>
  .table-wrapper {
    position: relative;
    .tools-bar {
      display: flex;
      justify-content: flex-end;
    }
  }

  // 挂载body class
  .filter-wrapper {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
</style>
